﻿namespace UnitTest_MSTestHelper
{
    using System;
    using System.Collections.Generic;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class When_testing_that_arguments_can_not_be_null
    {
        [TestMethod]
        public void OK_if_ArgumentNullException_is_thrown_with_the_correct_argument_name()
        {
            CommonTests.ArgumentCannotBeNull(
                () => { throw new ArgumentNullException("xxx"); },
                "xxx");
        }

        [TestMethod]
        public void Fails_if_argument_name_is_incorrect()
        {
            var exception = AssertEx.Throws<AssertFailedException>(() =>
                CommonTests.ArgumentCannotBeNull(
                    () =>
                    {
                        throw new ArgumentNullException("yyy");
                    },
                    "xxx"));
            AssertEx.That(() => exception.Message == "AssertEx failed. 'Message' was expected to be equal to be <Value cannot be null.\r\nParameter name: xxx> but was <Value cannot be null.\r\nParameter name: yyy>.");
        }

        [TestMethod]
        public void Fails_if_wrong_exception_thrown()
        {
            var exception = AssertEx.Throws<AssertFailedException>(() =>
                CommonTests.ArgumentCannotBeNull(
                    () =>
                    {
                        throw new NotSupportedException("yyy");
                    },
                    "yyy"));
            AssertEx.That(() => exception.Message == "Expected the action to throw an exception of type 'System.ArgumentNullException' but it threw one of type 'System.NotSupportedException'.");
        }

        [TestMethod]
        public void Fails_if_no_exception_is_thrown()
        {
            var exception = AssertEx.Throws<AssertFailedException>(() =>
                CommonTests.ArgumentCannotBeNull(
                    () =>
                    {
                    },
                    "xxx"));
            AssertEx.That(() => exception.Message == "Expected the action to throw an exception of type 'System.ArgumentNullException'.");
        }
    }

    [TestClass]
    public class When_testing_that_arguments_can_not_be_empty_string
    {
        [TestMethod]
        public void OK_if_ArgumentException_is_thrown_with_the_correct_argument_name()
        {
            CommonTests.ArgumentCannotBeEmptyString(
                () => { throw new ArgumentException("Value cannot be an empty string.", "xxx"); },
                "xxx");
        }

        [TestMethod]
        public void Fails_if_no_exception_is_thrown()
        {
            var exception = AssertEx.Throws<AssertFailedException>(() =>
                CommonTests.ArgumentCannotBeEmptyString(
                    () =>
                    {
                    },
                    "xxx"));
            AssertEx.That(() => exception.Message == "Expected the action to throw an exception of type 'System.ArgumentException'.");
        }

        [TestMethod]
        public void Fails_if_wrong_argument_name()
        {
            var exception = AssertEx.Throws<AssertFailedException>(() =>
                CommonTests.ArgumentCannotBeEmptyString(
                    () =>
                    {
                        throw new ArgumentException("Value cannot be an empty string.", "yyy");
                    },
                    "xxx"));
            AssertEx.That(() => exception.Message == "AssertEx failed. 'Message' was expected to be equal to be <Value cannot be an empty string.\r\nParameter name: xxx> but was <Value cannot be an empty string.\r\nParameter name: yyy>.");
        }
    }

    [TestClass]
    public class When_testing_that_arguments_can_not_be_trimmed_string
    {
        [TestMethod]
        public void OK_if_ArgumentException_is_thrown_with_the_correct_argument_name()
        {
            CommonTests.ArgumentCannotBeEmptyTrimmedString(
                value => { throw new ArgumentException("Value cannot be an empty string.", "xxx"); },
                "xxx");
        }

        [TestMethod]
        public void Empty_and_trimmable_string_are_tried()
        {
            // Build a list of the values tried.
            List<string> valuesTried = new List<string>();
            CommonTests.ArgumentCannotBeEmptyTrimmedString(
                value =>
                {
                    valuesTried.Add(value);
                    throw new ArgumentException("Value cannot be an empty string.", "xxx");
                },
                "xxx");

            // Make sure each can be trimmed to the empty string.
            foreach (string value in valuesTried)
            {
                AssertEx.That(() => value.Trim().Length == 0);
            }
        }

        [TestMethod]
        public void Fails_if_no_exception_is_thrown()
        {
            var exception = AssertEx.Throws<AssertFailedException>(() =>
                CommonTests.ArgumentCannotBeEmptyTrimmedString(
                    value =>
                    {
                    },
                    "xxx"));
            AssertEx.That(() => exception.Message == "The test failed on the following case #1: ()\r\nExpected the action to throw an exception of type 'System.ArgumentException'.");
        }

        [TestMethod]
        public void Fails_if_wrong_argument_name()
        {
            var exception = AssertEx.Throws<AssertFailedException>(() =>
                CommonTests.ArgumentCannotBeEmptyTrimmedString(
                    value =>
                    {
                        throw new ArgumentException("Value cannot be an empty string.", "yyy");
                    },
                    "xxx"));
            AssertEx.That(() => exception.Message == "The test failed on the following case #1: ()\r\nAssertEx failed. 'Message' was expected to be equal to be <Value cannot be an empty string.\r\nParameter name: xxx> but was <Value cannot be an empty string.\r\nParameter name: yyy>.");
        }
    }
}